structure Mir2code = 
struct
  structure M = Mir
  structure E = Env4Ir
  structure A = Assem

  (* using A.Directive(s) to add more instructions *)

  (* clean some redunctant jmp and label *)
  fun filt_jmp code =
      let fun filt [] = []
            | filt ((M.JMP(l))::code') = 
              (case code'
                of  (M.JMP(l'))::code'' => filt code'
                  |  _ => ((M.JMP(l))::(filt code')))
            | filt (i :: code') = i :: (filt code')
      in  List.rev(filt (List.rev code))
      end

  (* collect reachable labels *)
  fun col_lb code = 
      let fun fdfun (M.JMP(lb), lblist) = lb::lblist
	    | fdfun (M.CJMP(cop, e1, e2, lb1, lb2), lblist) = [lb1, lb2]@lblist
	    | fdfun (t, lblist) = lblist
      in List.foldl fdfun [] code
      end

  (* del non-reachable labels *)
  fun del_lab code = 
      let fun ex (l::r) l1 = if l = l1
			     then true
			     else ex r l1
	    | ex [] l1 = false
	  val al_lb = col_lb code
	  fun cl (M.Label(lb)) = if ex al_lb lb
				 then [M.Label(lb)]
				 else []
	    | cl t = [t]
      in List.concat(List.map cl code)
      end

  (* clean top*)
  fun clean_mir mir = 
      let val mir' = filt_jmp mir
      in del_lab mir'
      end 

  fun tr_off off = if off >= 0 
		   then Int.toString(off)
		   else "-"^Int.toString(0-off)
			
  fun sim_lval' (M.BINOP(M.PLUS, lval, M.CONST(i))) = 
      let val (node, off) = sim_lval' lval
      in (node, off+i)
      end
    | sim_lval' (M.NAME("_rev_ebp_")) = (M.NAME("_rev_ebp_"), 0)
    | sim_lval' (t) = (t, 0)

  fun sim_lval m = 
      let val (node, off) = sim_lval' m
      in M.BINOP(M.PLUS, node, M.CONST(off))
      end

  val C_env : E.env ref = ref []
  fun set_env env = C_env := env
 
  val C_senv : E.struct_env ref = ref []
  fun set_senv senv = C_senv := senv

  (* basic translation *)
  fun tr_aop M.PLUS = [A.Addr(A.Esi, A.Eax)]
    | tr_aop M.MINUS = [A.Subr(A.Esi, A.Eax)]
    | tr_aop M.MUL = [A.Mulr(A.Esi, A.Eax)]
    | tr_aop M.DIV = [A.Div(A.Esi)]
    | tr_aop M.MOD = [A.Div(A.Esi), A.Movr(A.Edx, A.Eax)]
    | tr_aop _ = []

  fun psh_arg' src treg init stp limit = 
      if init >= limit
      then []
      else ([A.Movld((0-init), src, treg),A.Push(treg)]@
	    (psh_arg' src treg (init + stp) stp limit))

  fun psh_arg (M.MEM(me1, size)) = if size > 4
				   then ((A.Addz(size-4, A.Eax))::(psh_arg' A.Eax A.Esi 0 4 size), size)
				   else ([A.Push(A.Eax)], 4)
    | psh_arg _ = ([A.Push(A.Eax)], 4)

  fun bk_copy (src, soff) treg (des,doff) init stp limit = 
      if init >= limit
      then []
      else ([(A.Movld(init+soff, src, treg)),(A.Movst(treg, init+doff, des))]@
	    (bk_copy (src, soff) treg (des,doff) (init + stp) stp limit))
  
  (* address will always in Ebx or indexed by Ebx + offset 
   * value(exp) will always ins Eax
   *)
  fun tr_lval' (M.BINOP(M.PLUS, M.NAME("_rev_ebp_"), M.CONST(off))) = ([], (A.Ebp, off))
    | tr_lval' (M.BINOP(M.PLUS, sub_lval, M.CONST(off))) = 
      let val (sub1', (bR, of1)) = tr_lval' sub_lval
      in (sub1', (bR, of1+off))
      end
    | tr_lval' (M.BINOP(M.PLUS, sub_lval, (M.BINOP(M.MUL, sub_exp, M.CONST(elemSize))))) = 
      let val (sub1', (bR, of1)) = tr_lval' sub_lval
	  val sube' = tr_exp sub_exp 
	  val n_sub1' = case bR
			 of A.Ebx => sube'@[A.Mulz(elemSize, A.Eax), A.Push(A.Eax)]@sub1'
				     @[A.Pop(A.Eax), A.Addz(of1, bR), A.Addr(A.Eax, bR)]
			  | A.Ebp => sube'@[A.Mulz(elemSize, A.Eax)]@sub1'
				     @[A.Movr(A.Ebp, A.Ebx), A.Addz(of1, A.Ebx), A.Addr(A.Eax, A.Ebx)]
			  | _ => raise Fail "bug\n"
      in (n_sub1', (A.Ebx, 0))
      end
    | tr_lval' (M.MEM(sub_lval, sz)) = 
      let val (sub1', (bR, of1)) = tr_lval' sub_lval
	  val n_sub1' = sub1'@[A.Movld(of1, bR, A.Ebx)]
      in (n_sub1', (A.Ebx, 0))
      end [("print", (false, ~2, Simple)),
       ("printb", (false, ~2, Simple)), 
       ("printp", (false, ~2, Simple)),
       ("alloc", (false, ~2, Simple)), 
       ("free", (false, ~2, Simple))]
    | tr_lval' (M.NAME(str)) = 
      let val n_sub1' = (fn "_rev_ebp_" => [A.Movr(A.Ebp, A.Eax)]
			  | _ => [A.Leal(str, A.Ebx)]) str
      in (n_sub1', (A.Ebx, 0))
      end
    | tr_lval' t = (tr_exp t, (A.Ebx, 0))

  and tr_lval t = tr_lval' t
(*  and tr_lval (M.BINOP(M.PLUS, M.NAME("_rev_ebp"), M.CONST(off))) = [A.Movr(A.Ebp, A.Eax), A.Addz(off, A.Eax)]
    | tr_lval (M.BINOP(M.PLUS, sub_lval, M.CONST(off))) = 
      let val t = tr_lval sub_lval
      in case sub_lval 
	  of (M.BINOP(M.PLUS, M.NAME("_rev_ebp_"), M.CONST(off1))) => 
	     tr_lval (M.BINOP(M.PLUS, M.NAME("_rev_ebp_"), M.CONST(off+off1)))
	   | _ => t@[A.Addz(off, A.Eax)]
      end
    | tr_lval (M.BINOP(M.PLUS, sub_lval, (M.BINOP(M.MUL, sub_exp, M.CONST(elemSize))))) = 
      let val sub_exp' = tr_exp sub_exp
	  val sub_lval' = tr_lval sub_lval
      in sub_exp'@[A.Mulz(elemSize, A.Eax), A.Movr(A.Eax, A.Esi)]@sub_lval'@[A.Addr(A.Esi, A.Eax)]
      end
    | tr_lval t = tr_exp t
*)
  and tr_exp (M.DUMMY) = []
    | tr_exp (M.CONST(i)) = [A.Movz(i, A.Eax)]
    | tr_exp (M.NAME(str)) = (fn "_rev_ebp_" => [A.Movr(A.Ebp, A.Eax)]
			       | _ => [A.Leal(str, A.Eax)]) str
    (* TEMP node only occur in BOOL type, so save it in A.Eax*)
    | tr_exp (M.TEMP(str, preins)) = 
      let val pre' = List.concat(List.map tr_lnode preins)
      in pre'
      end
    (* more instrs not in ASSEM *)
    | tr_exp (M.BINOP(M.PLUS, me1, M.CONST(1))) = 
      let val me1' = tr_exp me1
      in me1'@[A.Directive("\tincl\t%eax")]
      end
    | tr_exp (M.BINOP(M.MINUS, me1, M.CONST(1))) = 
      let val me1' = tr_exp me1
      in me1'@[A.Directive("\tdecl\t%eax")]
      end
    | tr_exp (M.BINOP(M.PLUS, M.MEM(me1, s1), me2)) = 
      let val me2' = tr_exp me2
	  val (sub_me1', (bR, of1)) = tr_lval me1
      in case bR
	  of A.Ebx => sub_me1'@[A.Push(A.Ebx)]@me2'@[A.Pop(A.Ebx), A.Directive("\taddl\t"^tr_off(of1)^"(%ebx), %eax")]
	   | A.Ebp => me2'@[A.Directive("\taddl\t"^tr_off(of1)^"(%ebp), %eax")]
	   | _ => raise Fail "bug\n"
      end
    | tr_exp (M.BINOP(M.PLUS, me1, M.MEM(me2, s1))) = tr_exp (M.BINOP(M.PLUS, M.MEM(me2, s1), me1))
(*
    | tr_exp (M.BINOP(M.MINUS, M.MEM(me1, s1), me2)) = 
      let val me2' = tr_exp me2
	  val me1_s = sim_lval me1
	  val me1' = (tr_lval me1)@[A.Movld(0, A.Eax, A.Eax)]
	  val maop' = tr_aop M.MINUS
      in case me1_s 
	  of (M.BINOP(M.PLUS, M.NAME("_rev_ebp_"), M.CONST(i))) => 
	     me2'@[A.Directive("\tsubl\t"^Int.toString(i)^"(%ebp), %eax")]
	   | _ => (me1'@[A.Push(A.Eax)]@me2'@[A.Pop(A.Esi), A.Xchg(A.Eax, A.Esi)]@maop')
      end
*)
    | tr_exp (M.BINOP(M.MINUS, me1, M.MEM(me2, s1))) = 
      let val me1' = tr_exp me1
	  val (sub_me2', (bR, of1)) = tr_lval me2
      in case bR
	  of A.Ebx => sub_me2'@[A.Push(A.Ebx)]@me1'@[A.Pop(A.Ebx), A.Directive("\tsubl\t"^tr_off(of1)^"(%ebx), %eax")]
	   | A.Ebp => me1'@[A.Directive("\tsubl\t"^tr_off(of1)^"(%ebp), %eax")]
	   | _ => raise Fail "bug\n"
      end

    | tr_exp (M.BINOP(M.MUL, M.MEM(me1, s1), me2)) = 
      let val me2' = tr_exp me2
	  val (sub_me1', (bR, of1)) = tr_lval me1
      in case bR
	  of A.Ebx => sub_me1'@[A.Push(A.Ebx)]@me2'@[A.Pop(A.Ebx), A.Directive("\timull\t"^tr_off(of1)^"(%ebx), %eax")]
	   | A.Ebp => me2'@[A.Directive("\timull\t"^tr_off(of1)^"(%ebp), %eax")]
	   | _ => raise Fail "bug\n"
      end
    | tr_exp (M.BINOP(M.MUL, me1, M.MEM(me2, s1))) = tr_exp (M.BINOP(M.MUL, M.MEM(me2, s1), me1))
    (* me1 & me2 should be of size 4 *)
    | tr_exp (M.BINOP(maop, me1, me2)) = 
      let val me1' = tr_exp me1
	  val me2' = tr_exp me2
	  val maop' = tr_aop maop
      in me1'@[A.Push(A.Eax)]@me2'@[A.Pop(A.Esi), A.Xchg(A.Eax, A.Esi)]@maop'
      end
    (* normal MEM, with size == 4, 
     may occur @subscript of accessing array, and BINOP node *)
    | tr_exp (M.MEM(me1, size)) = 
      let val (sub_me1', (bR, of1)) = tr_lval me1
      in sub_me1'@[A.Movld(of1, bR, A.Eax)]
      end
    | tr_exp (M.CALL(fid, palist)) = 
      let fun fdfun (pa, (intrs, argsize)) = 
	      let val (psh_ins, a_s) = psh_arg pa
	      in (intrs@(tr_exp pa)@(psh_ins), a_s+argsize)
	      end
          val (_, _, types) = Option.valOf(E.lookup fid (!C_env))
      in  case types
           of  E.Simple => let val (ins, argsize) = List.foldr fdfun ([],0) palist
                           in  ins@[A.Call(fid), A.Addz(argsize, A.Esp)]
                           end
             | E.Pointer(subtype) =>  let val (ins, argsize) = List.foldr fdfun ([],0) palist
                                      in  ins@[A.Call(fid), A.Addz(argsize, A.Esp)]
                                      end 
             | _ => let val retsize = E.calTypeSize types (!C_senv)
                        val (ins, argsize) = List.foldr fdfun ([],0) palist
                    in  [(A.Subz (retsize, A.Esp)), (A.Leab (0, A.Esp, A.Edi))]@
			ins@
			[(A.Push A.Edi), (A.Call fid), (A.Addz (argsize+4+retsize, A.Esp))]
                    end
      end
    | tr_exp _ = []

  and tr_lnode (M.Label(str)) = [A.Label(str, NONE)]
    | tr_lnode (M.JMP(str)) = [A.Jmp(str)]
    | tr_lnode (M.EXP(me)) = tr_exp me
    (* return value *)
    | tr_lnode (M.MOV(M.NAME("_rev_ret_"), me1)) = 
      let val me1' = tr_exp me1
      in case me1
	  of (M.MEM(me, size)) => if size > 4 
				  then (me1'@[A.Movld (8, A.Ebp, A.Ebx)]@(bk_copy (A.Eax,0) A.Esi (A.Ebx, 0) 0 4 size)@
                                       [A.Movld (8, A.Ebp, A.Eax)])
				  else me1'
	   | _ => me1'
      end
    (* temp value *)
    | tr_lnode (M.MOV(M.NAME(n), M.CONST(1))) = 
      if String.isPrefix "_T" n
      then [A.Movz(1, A.Eax)]
      else (let val me1' = tr_exp (M.NAME(n))
		val me2' = tr_exp (M.CONST(1))
	    in me1'@[A.Movr(A.Eax, A.Ebx)]@me2'@[A.Movst(A.Eax, 0, A.Ebx)]
	    end
	   )
    | tr_lnode (M.MOV(M.NAME(n), M.CONST(0))) = 
      if String.isPrefix "_T" n
      then [A.Movz(0, A.Eax)]
      else (let val me1' = tr_exp (M.NAME(n))
		val me2' = tr_exp (M.CONST(0))
	    in me1'@[A.Movr(A.Eax, A.Ebx)]@me2'@[A.Movst(A.Eax, 0, A.Ebx)]
	    end
	   )
    (* block copy *)
(*    | tr_lnode (M.MOV(me1, M.MEM(me2, size))) = 
      let val me1_s = sim_lval me1
	  val me2_s = sim_lval me2
	  fun ebpindx e = case e
			   of (M.BINOP(M.PLUS, M.NAME("_rev_ebp_"), M.CONST(i))) => (true, i)
			    | _ => (false, 0)

	  val me_b =  case ((ebpindx me1_s),(ebpindx me2_s))
		       of ((true, i1), (true, i2)) => [A.Movld(i2, A.Ebp, A.Eax), A.Movst(A.Eax, i1, A.Ebp)]

			| ((false, 0), (true, i2)) => 
			  ((tr_lval me1_s)@[A.Movld(i2, A.Ebp, A.Ebx), A.Movst(A.Ebx, 0, A.Eax)])

			| ((true, i1), (false, 0)) =>
			  ((tr_lval me2_s)@[A.Movld(0, A.Eax, A.Eax), A.Movst(A.Eax, i1, A.Ebp)])

			| ((false, 0), (false, 0)) =>
			  ((tr_lval me2_s)@[A.Movld(0, A.Eax, A.Eax), A.Push(A.Eax)])@
			  ((tr_lval me1_s)@[A.Pop(A.Ebx), A.Movst(A.Ebx, 0, A.Eax)])

			| _ => raise Fail "bug\n"

	  val me_b' = case ((ebpindx me1_s),(ebpindx me2_s))
		       of ((true, i1), (true, i2)) => bk_copy (A.Ebp, i2) A.Eax (A.Ebp, i1) 0 4 size
			| ((false, 0), (true, i2)) => (tr_lval me1_s)@(bk_copy (A.Ebp, i2) A.Esi (A.Eax, 0) 0 4 size)
			| ((true, i1), (false, 0)) => (tr_lval me2_s)@(bk_copy (A.Eax, 0) A.Esi (A.Ebp, i1) 0 4 size)
			| ((false, 0), (false, 0)) => (tr_lval me2_s)@[A.Push(A.Eax)]@(tr_lval me1_s)@[A.Pop(A.Ebx)]@
						      (bk_copy (A.Ebx, 0) A.Esi (A.Eax, 0) 0 4 size)
			| _ => raise Fail "bug\n"
      in if size = 4
	 then me_b
	 else me_b'
      end
*)
    | tr_lnode (M.MOV(me1, M.MEM(me2, size))) = 
      let val (me1', (bR1, of1)) = tr_lval me1
	  val (me2', (bR2, of2)) = tr_lval me2
	  val me_b = (fn (A.Ebp, A.Ebp) => [A.Movld(of2, A.Ebp, A.Eax), A.Movst(A.Eax, of1, A.Ebp)]
		       | (A.Ebx, A.Ebp) => me1'@[A.Movld(of2, A.Ebp, A.Eax), A.Movst(A.Eax, of1, A.Ebx)]
		       | (A.Ebp, A.Ebx) => me2'@[A.Movld(of2, A.Ebx, A.Eax), A.Movst(A.Eax, of1, A.Ebp)]
		       | (A.Ebx, A.Ebx) => me1'@[A.Push(A.Ebx)]@me2'
					   @[A.Pop(A.Eax), A.Movld(of2, A.Ebx, A.Ebx), A.Movst(A.Ebx, of1, A.Eax)]
		       | _ => raise Fail "bug\n"
		     ) (bR1, bR2)

	  val me_b' = (fn (A.Ebp, A.Ebp) => bk_copy (A.Ebp, of2) A.Eax (A.Ebp, of1) 0 4 size
			| (A.Ebx, A.Ebp) => me1'@(bk_copy (A.Ebp, of2) A.Eax (A.Ebx, of1) 0 4 size)
			| (A.Ebp, A.Ebx) => me2'@(bk_copy (A.Ebx, of2) A.Eax (A.Ebp, of1) 0 4 size)
			| (A.Ebx, A.Ebx) => me1'@[A.Push(A.Ebx)]@me2'
					   @[A.Pop(A.Eax)]@(bk_copy (A.Ebx, of2) A.Esi (A.Eax, of1) 0 4 size)
			| _ => raise Fail "bug\n"
		      ) (bR1, bR2)
      in if size = 4
	 then me_b
	 else me_b'
      end
    (* normal mov *)
    | tr_lnode (M.MOV(me1, me2)) = 
      let val (me1', (bR, of1)) = tr_lval me1
	  val me2' = tr_exp me2
      in case bR
	  of A.Ebx => me2'@[A.Push(A.Eax)]@me1'@[A.Pop(A.Eax), A.Movst(A.Eax, of1, A.Ebx)]
	   | A.Ebp => me2'@ [A.Movst(A.Eax, of1, A.Ebp)]
	   | _ => raise Fail "bug\n"
      end
    (* more instrs cannot be expressed in ASSEM *)
(*    | tr_lnode (M.CJMP(cop, me1, M.MEM(me2, sz), tlb, flb)) = 
      let val me1' = tr_exp me1
	  val me2_s = sim_lval me2

	  val me2' = tr_exp (M.MEM(me2, sz))
	  val cop' = (fn M.NE => [A.Beq(A.Esi, A.Eax, flb), A.Jmp(tlb)]
		       | M.EQ => [A.Beq(A.Esi, A.Eax, tlb), A.Jmp(flb)]
		       | M.LE => [A.Bge(A.Esi, A.Eax, tlb), A.Jmp(flb)]
		       | M.LT => [A.Bgt(A.Esi, A.Eax, tlb), A.Jmp(flb)]
		       | M.GE => [A.Bge(A.Eax, A.Esi, tlb), A.Jmp(flb)]
		       | M.GT => [A.Bgt(A.Eax, A.Esi, tlb), A.Jmp(flb)]) cop

	  fun cop_s' off = (fn M.NE => 
			       [A.Directive("\tcmpl\t%eax, "^tr_off(off)^"(%ebp)"), 
				A.Directive("\tje\t"^flb), 
				A.Jmp(tlb)]
			     | M.EQ => 
			       [A.Directive("\tcmpl\t%eax, "^tr_off(off)^"(%ebp)"), 
				A.Directive("\tje\t"^tlb), 
				A.Jmp(flb)]
			     | M.LE => 
			       [A.Directive("\tcmpl\t%eax, "^tr_off(off)^"(%ebp)"), 
				A.Directive("\tjge\t"^tlb), 
				A.Jmp(flb)]
			     | M.LT => 
			       [A.Directive("\tcmpl\t%eax, "^tr_off(off)^"(%ebp)"), 
				A.Directive("\tjg\t"^tlb), 
				A.Jmp(flb)]
			     | M.GE => 
			       [A.Directive("\tcmpl\t%eax, "^tr_off(off)^"(%ebp)"), 
				A.Directive("\tjle\t"^tlb), 
				A.Jmp(flb)]
			     | M.GT => 
			       [A.Directive("\tcmpl\t%eax, "^tr_off(off)^"(%ebp)"), 
				A.Directive("\tjl\t"^tlb), 
				A.Jmp(flb)]) cop
      in case me2_s 
	  of (M.BINOP(M.PLUS, M.NAME("_rev_ebp_"), M.CONST(i))) => 
	     me1'@(cop_s' i)
	   | _ => me1'@[A.Push(A.Eax)]@me2'@[A.Pop(A.Esi)]@cop'
      end
*)
    | tr_lnode (M.CJMP(cop, me1, M.MEM(me2, sz), tlb, flb)) = 
      let val me1' = tr_exp me1
	  val (me2', (bR, of2)) = tr_lval me2

	  fun tr_breg (A.Ebx) = "(%ebx)"
	    | tr_breg (A.Ebp) = "(%ebp)"
	    | tr_breg _ = raise Fail "bug\n"

	  fun cop_s' off = (fn M.NE => 
			       [A.Directive("\tcmpl\t%eax, "^tr_off(off)^tr_breg(bR)), 
				A.Directive("\tje\t"^flb), 
				A.Jmp(tlb)]
			     | M.EQ => 
			       [A.Directive("\tcmpl\t%eax, "^tr_off(off)^tr_breg(bR)),
				A.Directive("\tje\t"^tlb), 
				A.Jmp(flb)]
			     | M.LE => 
			       [A.Directive("\tcmpl\t%eax, "^tr_off(off)^tr_breg(bR)),
				A.Directive("\tjge\t"^tlb), 
				A.Jmp(flb)]
			     | M.LT => 
			       [A.Directive("\tcmpl\t%eax, "^tr_off(off)^tr_breg(bR)),
				A.Directive("\tjg\t"^tlb), 
				A.Jmp(flb)]
			     | M.GE => 
			       [A.Directive("\tcmpl\t%eax, "^tr_off(off)^tr_breg(bR)),
				A.Directive("\tjle\t"^tlb), 
				A.Jmp(flb)]
			     | M.GT => 
			       [A.Directive("\tcmpl\t%eax, "^tr_off(off)^tr_breg(bR)),
				A.Directive("\tjl\t"^tlb), 
				A.Jmp(flb)]) cop
      in case bR 
	  of A.Ebx => me1'@[A.Push(A.Eax)]@me2'@[A.Pop(A.Eax)]@(cop_s' of2)
	   | A.Ebp => (let val _ = (fn [] => ()
				     | _ => raise Fail "bug\n") me2'
		       in me1'@(cop_s' of2)
		       end
		      )
	   | _ => raise Fail "bug\n"
      end

    | tr_lnode (M.CJMP(cop, M.MEM(me1, sz), me2, tlb, flb)) =
      (fn M.NE => tr_lnode (M.CJMP(M.NE, me2, M.MEM(me1, sz), tlb, flb))
	| M.EQ => tr_lnode (M.CJMP(M.EQ, me2, M.MEM(me1, sz), tlb, flb))
	| M.LE => tr_lnode (M.CJMP(M.GE, me2, M.MEM(me1, sz), tlb, flb))
	| M.LT => tr_lnode (M.CJMP(M.GT, me2, M.MEM(me1, sz), tlb, flb))
	| M.GE => tr_lnode (M.CJMP(M.LE, me2, M.MEM(me1, sz), tlb, flb))
	| M.GT => tr_lnode (M.CJMP(M.LT, me2, M.MEM(me1, sz), tlb, flb))) cop

    | tr_lnode (M.CJMP(cop, me1, me2, tlb, flb)) = 
      let val me1' = tr_exp me1
	  val me2' = tr_exp me2
	  val cop' = (fn M.NE => [A.Beq(A.Esi, A.Eax, flb), A.Jmp(tlb)]
		       | M.EQ => [A.Beq(A.Esi, A.Eax, tlb), A.Jmp(flb)]
		       | M.LE => [A.Bge(A.Esi, A.Eax, tlb), A.Jmp(flb)]
		       | M.LT => [A.Bgt(A.Esi, A.Eax, tlb), A.Jmp(flb)]
		       | M.GE => [A.Bge(A.Eax, A.Esi, tlb), A.Jmp(flb)]
		       | M.GT => [A.Bgt(A.Eax, A.Esi, tlb), A.Jmp(flb)]) cop
      in me1'@[A.Push(A.Eax)]@me2'@[A.Pop(A.Esi)]@cop'
      end

  fun tmp_out' (t_mir, t_env, t_senv, pro, epi) = 
      let val _ = set_env t_env
	  val _ = set_senv t_senv
	  val t_mir1 = clean_mir t_mir
	  val t_mir' = Aux4Mir.aux_top t_mir1
	  val text = pro@(List.concat(List.map tr_lnode t_mir'))@epi
          val code =String.concat((List.map (ToString.toString true []) text))
      in code^"\n\n\n"
      end 

  fun tmp_out (t_mir, data) = 
      let val assemblyfile = TextIO.openOut((!ErrorMsg.fileName)^"xx.s")
          val whole = String.concat(List.map tmp_out' t_mir)
          val dataseg =String.concat((List.map(ToString.toString true []) data))
      in  TextIO.output(assemblyfile, whole^dataseg);
          TextIO.closeOut(assemblyfile)
      end

  fun emitCode' (t_mir, t_env, t_senv, pro, epi) = 
      let val _ = set_env t_env
	  val _ = set_senv t_senv
	  val t_mir1 = clean_mir t_mir
	  val t_mir' = Aux4Mir.aux_top t_mir1
	  val text = pro@(List.concat(List.map tr_lnode t_mir'))@epi
      in  text
      end

  fun emitCode mirlist = List.concat (List.map emitCode' mirlist)
end 
